/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package recognize;

import com.googlecode.javacv.cpp.videoInputLib.*;
import static com.googlecode.javacv.cpp.opencv_core.*;
import static com.googlecode.javacv.cpp.opencv_objdetect.*;
import com.googlecode.javacv.cpp.opencv_core.CvRect;
import com.googlecode.javacv.cpp.opencv_core.CvSeq;
import com.googlecode.javacv.cpp.opencv_core.IplImage;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import util.Utils;

/**
 *
 * @author Progresywny Maciek
 */
public class RecognizeObjectsOpenCV {

    private CvHaarClassifierCascade classifier;
    private CvMemStorage storage;
    private long detectStartTime = 0;
    private String faceCascace = "c:\\head.xml";
    private int im_scale = 1;
    private int small_move = 5;
    private Rectangle faceRect;

    public RecognizeObjectsOpenCV() {
        initDetector();
        faceRect = new Rectangle();
    }

    public RecognizeObjectsOpenCV(String faceCascace) {
        this.faceCascace = faceCascace;
        initDetector();
        faceRect = new Rectangle();
    }

    public synchronized Rectangle[] recognize(BufferedImage image) {
        BufferedImage imageCopy = Utils.deepCopy(image);
        return trackFace(RgbToGrayscale(imageCopy));
    }

    private synchronized Rectangle[] trackFace(BufferedImage img) {
        detectStartTime = System.currentTimeMillis();
        IplImage grabbedImage = IplImage.createFrom(img);
        CvRect[] rect = findFace(grabbedImage);
     
       
        return getRectangle(rect);
    }

    private synchronized void initDetector() {
        classifier = new CvHaarClassifierCascade(cvLoad(faceCascace));
        if (classifier.isNull()) {
            System.out.println("\nCould not load the classifier file: " + faceCascace);
        }
        storage = CvMemStorage.create();

    }

    private synchronized CvRect[] findFace(IplImage grayIm) {
        CvSeq faces = cvHaarDetectObjects(grayIm, classifier, storage, 1.1, 3, // 3
                // CV_HAAR_SCALE_IMAGE |
                CV_HAAR_DO_CANNY_PRUNING);
        CvRect[] rect = null;
        int total = faces.total();
        if (total == 0) {
            //System.out.println("No faces found");
            return null;
        } else if (total > 1) // this case should not happen, but included for safety
        {
            //System.out.println("Multiple faces detected (" + total + "); using the first");
            rect = new CvRect[total];
            for (int i = 0; i < total; i++) {
                rect[i] = new CvRect(cvGetSeqElem(faces, i));
            }
        } else {
            //System.out.println("Face detected");
            rect = new CvRect[1];
            rect[0] = new CvRect(cvGetSeqElem(faces, 0));
        }
        cvClearMemStorage(storage);
        return rect;
    }  // end of findface()

    private synchronized BufferedImage RgbToGrayscale(BufferedImage image) {
        for (int i = 0; i < image.getWidth(); i++) {
            for (int j = 0; j < image.getHeight(); j++) {
                int color = image.getRGB(i, j);
                int alpha = (color >> 24) & 255;
                int red = (color >> 16) & 255;
                int green = (color >> 8) & 255;
                int blue = (color) & 255;
                final int lum = (int) (0.3 * red + 0.59 * green + 0.11 * blue);
                alpha = (alpha << 24);
                red = (lum << 16);
                green = (lum << 8);
                blue = lum;
                color = alpha + red + green + blue;
                image.setRGB(i, j, color);
            }
        }
        return image;
    }

    private synchronized Rectangle[] getRectangle(CvRect[] r) {
        if(r==null){
            return null;
        }
        else{
        Rectangle[] rectangles=new Rectangle[r.length];
        for (int i = 0; i < r.length; i++) {
            int xNew = 0;
            int yNew = 0;
            int widthNew = 0;
            int heightNew = 0;
                xNew = r[i].x();
                yNew = r[i].y();
                widthNew = r[i].width();
                heightNew = r[i].height();

                
            rectangles[i] = new Rectangle(xNew, yNew, widthNew, heightNew);
        }
        return rectangles;
        }
    }
}
